import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
import 'package:pui_flutter/src/constants/pui_constants.dart';
import 'package:pui_flutter/src/theme/pp_multistate_theme.dart';

/// 操作按钮回调
typedef PPMultiStateOperateFunc = void Function(PPMultiState state);

abstract class _MultiStateWidgetAbstract {
  /// 内容布局
  Widget attachContentWidget();

  /// 加载状态布局
  Widget attachLoadingWidget();

  /// 异常状态布局
  Widget attachExceptionWidget(PPMultiStateConfig config);
}

class PPMultiStateLayout extends StatefulWidget {
  /// 状态管理控制器
  final PPMultiStateMixin controller;

  /// 多状态下包裹的内容视图
  final Widget body;

  /// 初始化显示的状态
  final PPMultiState? initState;

  /// 空状态
  final PPMultiStateConfig? emptyState;

  /// 空状态
  final PPMultiStateConfig? exceptionState;

  /// 自定义状态
  final PPMultiStateConfig? customState;

  /// 重试按钮回调
  final PPMultiStateOperateFunc? onOperateFunc;

  /// 嵌套 expanded，默认为false，如果是在 Column 使用 PPMultiStateLayout 时需要传true
  final bool expanded;

  const PPMultiStateLayout({
    required this.body,
    required this.controller,
    this.initState = PPMultiState.CONTENT,
    this.emptyState,
    this.exceptionState,
    this.customState,
    this.onOperateFunc,
    this.expanded = false,
  });

  @override
  State<StatefulWidget> createState() => _PPMultiStateLayoutState();
}

/// 多状态布局State
class _PPMultiStateLayoutState extends State<PPMultiStateLayout>
    implements _MultiStateWidgetAbstract {
  _MultiStateNotifier? _mode;

  PPMultiStateMixin get controller {
    return widget.controller;
  }

  @override
  void initState() {
    controller.mEmptyState.merge(widget.emptyState);
    controller.mExceptionState.merge(widget.exceptionState);
    controller.mCustomState.merge(widget.customState);
    if (widget.onOperateFunc != null) {
      controller._mOperateFunc = widget.onOperateFunc;
    }
    // 尝试修改初始化状态
    if (widget.initState != null) {
      controller.cState.setValueWithNoNotify(widget.initState);
    }
  }

  @override
  void didChangeDependencies() {
    _updateListener();
    super.didChangeDependencies();
  }

  @override
  void didUpdateWidget(PPMultiStateLayout oldWidget) {
    _updateListener();
    super.didUpdateWidget(oldWidget);
  }

  void _updateListener() {
    _MultiStateNotifier newMode = widget.controller.cState;
    if (newMode != _mode) {
      _mode?.removeListener(_update);
      _mode = newMode;
      _mode?.addListener(_update);
    }
  }

  void _update() {
    if (mounted) setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    Widget resultWidget;
    PPMultiState state = controller.cState.value;
    switch (state) {
      case PPMultiState.LOADING:
        resultWidget = attachLoadingWidget();
        break;
      case PPMultiState.EMPTY:
        resultWidget = attachExceptionWidget(controller.mEmptyState);
        break;
      case PPMultiState.EXCEPTION:
        resultWidget = attachExceptionWidget(controller.mExceptionState);
        break;
      case PPMultiState.CUSTOM:
        // 自定义异常状态
        resultWidget = attachExceptionWidget(controller.mCustomState);
        break;
      default:
        // 内容状态
        resultWidget = attachContentWidget();
        break;
    }
    return wrapExpandedMultiView(
        widget.expanded, resultWidget, state != PPMultiState.LOADING);
  }

  @override
  Widget attachContentWidget() => widget.body;

  @override
  Widget attachLoadingWidget() => Container(
        padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Lottie.asset(
              'assets/loading/pui_loading_anim.zip',
              package: PUIGlobalConstant.packageName,
              animate: true,
              width: 76,
              height: 76,
            ),
            Container(
              margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 14),
              child: const Text(
                "加载中，请稍后...",
                style: TextStyle(color: Color(0xFF666666), fontSize: 15),
              ),
            ),
          ],
        ),
      );

  /// 根据状态配置生成异常视图
  @override
  Widget attachExceptionWidget(PPMultiStateConfig config) {
    List<Widget> columnChildren = [
      Image.asset(
        config.iconAssetsPath,
        width: 140,
        height: 140,
        package: config.package,
      ),
      Container(
        margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 14),
        child: Text(
          config.title,
          style: const TextStyle(color: Colors.black54, fontSize: 15),
        ),
      ),
    ];
    if (config.isShowOperateView) {
      columnChildren
          .add(_buildButtonWidget(config, widget.controller._onOperateFunc));
    }
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: columnChildren,
    );
  }

  Widget _buildButtonWidget(PPMultiStateConfig config, VoidCallback onPressed) {
    return GestureDetector(
      onTap: onPressed,
      child: Center(
        child: Container(
          padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
          decoration: BoxDecoration(
            gradient: LinearGradient(colors: config.buttonGradient),
            borderRadius: BorderRadius.circular(22),
          ),
          child: Text(
            config.operateText,
            overflow: TextOverflow.ellipsis,
            maxLines: 1,
            style: const TextStyle(color: Colors.white),
          ),
        ),
      ),
    );
  }

  /// 包裹装饰多状态布局，添加高度权重和显示动画
  Widget wrapExpandedMultiView(
      bool expanded, Widget sourceWidget, bool needFadeAnim) {
    Widget coreWidget = Center(
      child: AnimatedSwitcher(
        duration: Duration(milliseconds: (needFadeAnim ? 380 : 0)),
        reverseDuration: const Duration(milliseconds: 0),
        child: sourceWidget,
      ),
    );
    return expanded
        ? Expanded(
            flex: 1,
            child: coreWidget,
          )
        : LayoutBuilder(builder: (context, constraints) {
            return SizedBox(
              width: constraints.maxWidth,
              height: constraints.maxHeight,
              child: coreWidget,
            );
          });
  }
}

mixin PPMultiStateMixin {
  /// 空状态配置对象
  PPMultiStateConfig mEmptyState = PPMultiStateConfig.empty();

  /// 异常状态配置对象
  PPMultiStateConfig mExceptionState = PPMultiStateConfig.exception();

  /// 自定义状态配置对象
  PPMultiStateConfig mCustomState = PPMultiStateConfig.custom();

  /// 当前状态
  _MultiStateNotifier cState = _MultiStateNotifier(PPMultiState.CONTENT);

  /// 重试按钮方法回调
  PPMultiStateOperateFunc? _mOperateFunc;

  void changeState(
    PPMultiState toState, {
    String? iconAssetsPath,
    String? title,
    String? operateText,
    bool? isShowOperateView,
  }) {
    if (toState == PPMultiState.EXCEPTION) {
      mExceptionState.mergeBy(
          iconAssetsPath, title, operateText, isShowOperateView);
      cState.invalidate = true;
    } else if (toState == PPMultiState.CUSTOM) {
      mCustomState.mergeBy(
          iconAssetsPath, title, operateText, isShowOperateView);
      cState.invalidate = true;
    }
    cState.value = toState;
  }

  void _onOperateFunc() {
    if (_mOperateFunc != null) {
      _mOperateFunc!(cState.value);
      return;
    }
    if (kDebugMode) {
      debugPrint("点击了操作按钮，但操作回调未实现");
    }
  }
}

/// 容器状态包装类，作为被观察者可被注册。
/// 当控件状态值发生变化时，会触发所有监听者执行回调
/// 可通过 addListener(VoidCallback listener) 注册监听
class _MultiStateNotifier<PPMultiState> extends ChangeNotifier
    implements ValueListenable<PPMultiState> {
  /// Creates a [_MultiStateNotifier] that wraps this value.
  _MultiStateNotifier(this._value);

  PPMultiState _value;

  bool invalidate = false;

  @override
  PPMultiState get value => _value;

  set value(PPMultiState newValue) {
    if (invalidate || _value != newValue) {
      _value = newValue;
      notifyListeners();
    }
  }

  void setValueWithNoNotify(PPMultiState newValue) {
    if (_value == newValue) return;
    _value = newValue;
  }
}
